/*
 * Copyright 2009 original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.configleon.configurer;

import com.configleon.resource.PropertyResources;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

import java.util.Set;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;

/**
 * A special properties configurator that loads the Spring property files
 * based on a JVM parameter.
 */
public abstract class AbstractPropertyConfigurer extends PropertyPlaceholderConfigurer implements InitializingBean {

    public static final String JVM_VARIABLE_NAME = "configLocation";

    private PropertyResources propertyResources;

    /**
     * After the bean factory loads then configure project specific settings.
     */
    public void afterPropertiesSet()
            throws Exception {

        String configLocation = System.getProperty(JVM_VARIABLE_NAME);

        if (!StringUtils.hasText(configLocation)) {
            String msg = "The configLocation variable is not specified in the JVM settings!";
            logger.error(msg);
            throw new IllegalStateException(msg);
        }

        if (logger.isInfoEnabled()) {
            logger.info("The configLocation JVM variable is " + configLocation);
        }

        Properties properties = loadProperties(configLocation);
        postConfiguration(properties);
    }

    private Properties loadProperties(String configLocation)
            throws IOException {
        Properties properties = new Properties();
        List<Resource> resources = propertyResources.getResources(configLocation);
        for (Resource resource : resources) {
            properties.load(resource.getInputStream());
            if (logger.isDebugEnabled()) {
                logger.debug("Loading resource " + resource.getFilename());
            }
        }
        setProperties(properties);

        Config.setProperties(properties);

        if (logger.isDebugEnabled()) {
            for (Object key : sortedKeys(properties)) {
                logger.debug("property: " + key + " --> " + properties.get(key));
            }
        }

        return properties;
    }

    protected void postConfiguration(Properties properties) {
        // by default does not do anything
    }

    /**
     * Sort the property keys so that it is easier to debug.
     */
    private List sortedKeys(Properties properties) {
        Set keys = properties.keySet();
        List sortedKeys = new ArrayList(keys);
        Collections.sort(sortedKeys);
        return sortedKeys;
    }

    public void setPropertyResources(PropertyResources propertyResources) {
        this.propertyResources = propertyResources;
    }
}
